﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using io = System.IO;
using wf = System.Windows.Forms;
using System.Threading;

namespace editor.app
{
    /// <summary>
    /// RPackWindow.xaml 的交互逻辑
    /// </summary>
    public partial class RPackWindow : Window
    {
        const string EXT_NAME = comm.objst.RPack.FILE_EXT_NAME;

        comm.objst.RPack _rpack = null;
        string _fileName = "";
        string _sign = "";
        BitmapImage _iconImage = null, _iconKFAnim = null, _iconSprite = null;
        string _selKey = null;
        string _openResKey = null;

        Dictionary<string, Func<string, UserControl>> _resFuncDic = new Dictionary<string, Func<string, UserControl>>();

        public RPackWindow(string fileName = null, string openResKey = null)
        {
            InitializeComponent();
            this.LoadConfig1();

            WindowState = WindowState.Maximized;

            _openResKey = openResKey;

            _iconImage = new BitmapImage();
            _iconImage.FromFile("icon/image.png");

            _iconKFAnim = new BitmapImage();
            _iconKFAnim.FromFile("icon/kfanim.png");

            _iconSprite = new BitmapImage();
            _iconSprite.FromFile("icon/sprite.png");

            imgImage.Source = _iconImage;
            imgKFAnim.Source = _iconKFAnim;
            imgSprite.Source = _iconSprite;

            _resFuncDic.Add(typeof(comm.objst.RImage).Name, resKey => { return new RImage(_rpack, resKey); });
            _resFuncDic.Add(typeof(comm.objst.RKeyFrameAnim).Name, resKey => { return new RKFAnim(_rpack, resKey); });
            _resFuncDic.Add(typeof(comm.objst.RSprite).Name, resKey => { return new RSprite(_rpack, resKey); });

            if (fileName != null)
            {
                _fileName = fileName;
                OpenFile();
            }

            KeyDown += new KeyEventHandler(RPackWindow_KeyDown);
            btnNew.Click += new RoutedEventHandler(btnNew_Click);
            btnNewSprite.Click += new RoutedEventHandler(btnNewSprite_Click);
            btnNewImage.Click += new RoutedEventHandler(btnNewImage_Click);
            btnNewKFAnim.Click += new RoutedEventHandler(btnNewKFAnim_Click);
            btnReload.Click += new RoutedEventHandler(btnReload_Click);
            btnEditTag.Click += new RoutedEventHandler(btnEditTag_Click);

            comm.ThreadHelper.Run(() =>
            {
                while (true)
                {
                    if (_rpack != null)
                    {
                        var isChange = CheckSignChange();
                        Dispatcher.Invoke(new Action(() =>
                        {
                            Title = io.Path.GetFileName(_fileName) + (isChange ? "*" : "");
                        }));
                    }
                    Thread.Sleep(100);
                }
            });
        }

        void btnEditTag_Click(object sender, RoutedEventArgs e)
        {
            var keys = _rpack.GetAllResourceKeys();
            var sb = new StringBuilder();
            sb.Append("{\r\n");
            foreach (var key in keys)
            {
                var res = _rpack.GetResource(key);
                sb.Append("  \"" + key + "\":[\"" + res.Tag + "\",\"" + res.Name + "\"],\r\n");
            }
            if (sb.Length > 0)
            {
                sb.Remove(sb.Length - 3, 3);
            }
            sb.Append("\r\n}");
            var w = new TextWindow
            {
                Width = 600,
                Height = 480,
                InputText = sb.ToString(),
                ShowInTaskbar = false
            };
            w.ShowDialog();
            try
            {
                var dic = comm.JsonSerializer.Deserialize<Dictionary<string, string[]>>(w.InputText);
                if (dic != null)
                {
                    foreach (var key in dic.Keys)
                    {
                        var res = _rpack.GetResource(key);
                        if (res != null)
                        {
                            var arr = dic[key];
                            if (arr.Length == 2)
                            {
                                res.Tag = arr[0];
                                res.Name = arr[1];
                            }
                        }
                    }
                    FillList();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        void btnReload_Click(object sender, RoutedEventArgs e)
        {
            if (_fileName != null)
            {
                OpenFile();
            }
        }
        void RPackWindow_KeyDown(object sender, KeyEventArgs e)
        {
            if (Keyboard.Modifiers == ModifierKeys.Control)
            {
                if (e.Key == Key.S)
                {
                    SaveFile();
                }
                else if (e.Key == Key.W)
                {
                    brMain.Child = null;
                    FillList();
                }
            }
        }
        void btnNew_Click(object sender, RoutedEventArgs e)
        {
            var sfd = new wf.SaveFileDialog { Filter = EXT_NAME + "|*" + EXT_NAME };
            if (sfd.ShowDialog().ToString() == "OK")
            {
                _rpack = new comm.objst.RPack();
                _fileName = sfd.FileName;
                SaveFile();
                OpenFile();
            }
        }
        void btnNewSprite_Click(object sender, RoutedEventArgs e)
        {
            var guid = comm.GUID.NewString();
            _rpack.ResourceDic.Add(guid, new comm.objst.RSprite { Name = guid });
            FillList();
        }
        void btnNewKFAnim_Click(object sender, RoutedEventArgs e)
        {
            var guid = comm.GUID.NewString();
            _rpack.ResourceDic.Add(guid, new comm.objst.RKeyFrameAnim { Name = guid });
            FillList();
        }
        void btnNewImage_Click(object sender, RoutedEventArgs e)
        {
            var guid = comm.GUID.NewString();
            _rpack.ResourceDic.Add(guid, new comm.objst.RImage { Name = guid });
            FillList();
        }
        void btnEditRes_Click(object sender, RoutedEventArgs e)
        {
            var btn = (Button)sender;
            var parent = (Grid)btn.Parent;
            var resKey = parent.Tag.ToString();
            _selKey = resKey;
            FillList();

            if (_resFuncDic.ContainsKey(btn.Tag.ToString()))
            {
                brMain.Child = _resFuncDic[btn.Tag.ToString()](resKey);
            }
        }
        void btnDelRes_Click(object sender, RoutedEventArgs e)
        {
            var btn = (Button)sender;
            var parent = (FrameworkElement)btn.Parent;
            var key = parent.Tag.ToString();
            if (_rpack.ResourceDic.ContainsKey(key))
            {
                _rpack.ResourceDic.Remove(key);
                FillList();
            }

            if (brMain.Child != null && brMain.Child is IResEditControl)
            {
                var uc = ((IResEditControl)brMain.Child);
                if (uc.GetResKey() == key)
                {
                    brMain.Child = null;
                }
                else
                {
                    uc.Reload();
                }
            }
        }
        void textboxRes_TextChanged(object sender, TextChangedEventArgs e)
        {
            var textbox = (TextBox)sender;
            var parent = (FrameworkElement)textbox.Parent;
            var key = parent.Tag.ToString();
            if (_rpack.ResourceDic.ContainsKey(key))
            {
                var item = _rpack.GetResource(key);
                item.Name = textbox.Text;
            }
        }

        void FillList()
        {
            var tagColorDic = new Dictionary<string, Color>();

            spRes.Children.Clear();
            var spDic = new Dictionary<string, StackPanel>();
            var keys = _rpack.GetAllResourceKeys();
            foreach (var key in keys)
            {
                var item = _rpack.GetResource(key);
                var typeName = item.GetType().Name;
                if (!spDic.ContainsKey(typeName))
                {
                    var ep = new Expander { Header = new TextBlock { Text = typeName, Foreground = new SolidColorBrush(Color2.Black(50)), FontWeight = FontWeights.Bold, }, BorderThickness = new Thickness(1), Margin = new Thickness(0, 0, 0, 2), IsExpanded = true };
                    var sp = new StackPanel();
                    ep.Content = sp;
                    spRes.Children.Add(ep);

                    spDic.Add(typeName, sp);
                }

                #region btnText
                var btnText = "Edit";
                BitmapImage bitmap = null;
                if (item is comm.objst.RImage)
                {
                    var rimage = (comm.objst.RImage)item;
                    btnText = "E(" + rimage.FrameList.Count + ")";
                    bitmap = _iconImage;
                }
                else if (item is comm.objst.RKeyFrameAnim)
                {
                    var kfanim = (comm.objst.RKeyFrameAnim)item;
                    btnText = "E(" + kfanim.TimeList.Count + "/" + kfanim.ImageDic.Count + ")";
                    bitmap = _iconKFAnim;
                }
                else if (item is comm.objst.RSprite)
                {
                    var sprite = (comm.objst.RSprite)item;
                    btnText = "E(" + sprite.GroupDic.Count + ")";
                    bitmap = _iconSprite;
                }
                #endregion

                var grid = new Grid
                {
                    Tag = key,
                    Margin = new Thickness(0, 4, 0, 0)
                };

                #region textbox
                var textbox = new TextBox
                {
                    Text = item.Name,
                    Background = null,
                    BorderThickness = new Thickness(0),
                    Margin = new Thickness(36, 0, 60, 0),
                    VerticalAlignment = VerticalAlignment.Center
                };
                textbox.TextChanged += new TextChangedEventHandler(textboxRes_TextChanged);
                #endregion

                #region icon
                var icon = new Image
                {
                    Width = 16,
                    Height = 16,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    Margin = new Thickness(22, 0, 0, 0),
                    VerticalAlignment = VerticalAlignment.Center
                };
                icon.Source = bitmap;
                #endregion

                #region btnDel
                var btnDel = new Button
                {
                    Content = "X",
                    Focusable = false,
                    Width = 20,
                    Height = 24,
                    HorizontalAlignment = HorizontalAlignment.Left,
                    VerticalAlignment = VerticalAlignment.Center
                };
                btnDel.Click += new RoutedEventHandler(btnDelRes_Click);
                #endregion

                #region btnEdit
                var btnEdit = new Button { Content = btnText, Tag = typeName, Focusable = false, Width = 60, Height = 24, HorizontalAlignment = HorizontalAlignment.Right, VerticalAlignment = VerticalAlignment.Center };
                btnEdit.Click += new RoutedEventHandler(btnEditRes_Click);

                if (_selKey == key)
                {
                    btnEdit.Background = new SolidColorBrush(Color2.Orange(70));
                }
                #endregion

                var spTag = new StackPanel
                {
                    Margin = new Thickness(0, 0, 60, 0),
                    HorizontalAlignment = HorizontalAlignment.Right,
                    VerticalAlignment = VerticalAlignment.Top,
                    Orientation = Orientation.Horizontal
                };

                var tags = item.Tag.Split(',');
                foreach (var tag in tags)
                {
                    if (tag == "")
                    {
                        continue;
                    }
                    if (!tagColorDic.ContainsKey(tag))
                    {
                        tagColorDic.Add(tag, Color.FromRgb(
                            (byte)comm.MathHelper.RandomInt(0, 256),
                            (byte)comm.MathHelper.RandomInt(0, 256),
                            (byte)comm.MathHelper.RandomInt(0, 256)));
                    }
                    spTag.Children.Add(new Border
                    {
                        Width = 8,
                        Height = 8,
                        CornerRadius = new CornerRadius(6),
                        Margin = new Thickness(0, 0, 4, 0),
                        Background = new SolidColorBrush(tagColorDic[tag])
                    });
                }

                grid.Children.Add(btnDel);
                grid.Children.Add(icon);
                grid.Children.Add(textbox);
                grid.Children.Add(btnEdit);
                grid.Children.Add(spTag);
                spDic[typeName].Children.Add(grid);
            }
        }
        void SaveFile()
        {
            try
            {
                var bytes = comm.BinarySerializer.Serialize(_rpack);
                io.File.WriteAllBytes(_fileName, bytes);
                MakeSign();
            }
            catch (Exception ex)
            {
                MessageBox.Show("save file:" + _fileName + " err!" + ex.Message);
            }
        }
        void OpenFile()
        {
            try
            {
                _rpack = comm.BinarySerializer.Deserialize<comm.objst.RPack>(io.File.ReadAllBytes(_fileName));
                brMain.Child = null;
                MakeSign();

                if (_selKey != null)
                {
                    _openResKey = _selKey;
                }

                if (_openResKey != null)
                {
                    var res = _rpack.GetResource(_openResKey);
                    if (res != null)
                    {
                        _selKey = _openResKey;
                        brMain.Child = _resFuncDic[res.GetType().Name](_openResKey);
                    }
                }

                FillList();
            }
            catch (Exception ex)
            {
                MessageBox.Show("open file:" + _fileName + " err!" + ex.Message);
            }
        }
        void MakeSign()
        {
            _sign = comm.Safety.SHA1Encode(comm.BinarySerializer.Serialize(_rpack));
        }
        bool CheckSignChange()
        {
            return _sign != comm.Safety.SHA1Encode(comm.BinarySerializer.Serialize(_rpack));
        }
    }
}
